$LOAD_PATH.unshift "./lib"
require 'benchmark'
require 'rspec/expectations'

extend RSpec::Matchers

sizes = [10, 100, 1000, 2000]

puts "rspec-expectations #{RSpec::Expectations::Version::STRING} -- #{RUBY_ENGINE}/#{RUBY_VERSION}"

puts
puts "Passing `match_array` expectation with lists of integers including duplicate values"
puts

Benchmark.benchmark do |bm|
  sizes.each do |size|
    actual    = Array.new(size) { rand(size / 2) }
    expecteds = Array.new(3)    { actual.shuffle }
    expecteds.each do |expected|
      bm.report("#{size.to_s.rjust(5)} items") do
        expect(actual).to match_array(expected)
      end
    end
  end
end

__END__

Before new composable matchers algo:

   10 items  0.000000   0.000000   0.000000 (  0.000665)
   10 items  0.000000   0.000000   0.000000 (  0.000027)
   10 items  0.000000   0.000000   0.000000 (  0.000015)
  100 items  0.000000   0.000000   0.000000 (  0.000250)
  100 items  0.000000   0.000000   0.000000 (  0.000176)
  100 items  0.000000   0.000000   0.000000 (  0.000181)
 1000 items  0.010000   0.000000   0.010000 (  0.013612)
 1000 items  0.020000   0.000000   0.020000 (  0.013409)
 1000 items  0.020000   0.000000   0.020000 (  0.018222)
 2000 items  0.060000   0.000000   0.060000 (  0.057428)
 2000 items  0.060000   0.000000   0.060000 (  0.058242)
 2000 items  0.060000   0.000000   0.060000 (  0.063026)

After:

   10 items  0.000000   0.000000   0.000000 (  0.001835)
   10 items  0.000000   0.000000   0.000000 (  0.000327)
   10 items  0.000000   0.000000   0.000000 (  0.000336)
  100 items  0.030000   0.000000   0.030000 (  0.025134)
  100 items  0.030000   0.000000   0.030000 (  0.032476)
  100 items  0.020000   0.000000   0.020000 (  0.024273)
 1000 items  2.600000   0.040000   2.640000 (  2.649328)
 1000 items  2.510000   0.020000   2.530000 (  2.523448)
 1000 items  2.470000   0.000000   2.470000 (  2.476770)
 2000 items 11.590000   0.110000  11.700000 ( 11.719525)
 2000 items 10.750000   0.080000  10.830000 ( 10.845655)
 2000 items 11.140000   0.080000  11.220000 ( 11.241852)

With "smaller subproblem" optimization: (about 35% faster)

   10 items  0.000000   0.000000   0.000000 (  0.001236)
   10 items  0.000000   0.000000   0.000000 (  0.000278)
   10 items  0.000000   0.000000   0.000000 (  0.000293)
  100 items  0.010000   0.000000   0.010000 (  0.013229)
  100 items  0.020000   0.000000   0.020000 (  0.013932)
  100 items  0.020000   0.000000   0.020000 (  0.019739)
 1000 items  1.580000   0.030000   1.610000 (  1.622586)
 1000 items  1.670000   0.020000   1.690000 (  1.683174)
 1000 items  1.570000   0.010000   1.580000 (  1.588718)
 2000 items  7.030000   0.100000   7.130000 (  7.139178)
 2000 items  7.220000   0.090000   7.310000 (  7.328606)
 2000 items  6.930000   0.130000   7.060000 (  7.070295)

With "implement `values_match?` ourselves" optimization: (about 20% faster)

   10 items  0.000000   0.000000   0.000000 (  0.001352)
   10 items  0.000000   0.000000   0.000000 (  0.000313)
   10 items  0.000000   0.000000   0.000000 (  0.000298)
  100 items  0.010000   0.000000   0.010000 (  0.011200)
  100 items  0.010000   0.000000   0.010000 (  0.013465)
  100 items  0.020000   0.000000   0.020000 (  0.021589)
 1000 items  1.320000   0.030000   1.350000 (  1.350071)
 1000 items  1.280000   0.020000   1.300000 (  1.298206)
 1000 items  1.370000   0.010000   1.380000 (  1.392149)
 2000 items  6.120000   0.110000   6.230000 (  6.252104)
 2000 items  6.170000   0.090000   6.260000 (  6.270807)
 2000 items  5.910000   0.150000   6.060000 (  6.066389)

With `match_when_sorted?` optimization: (many orders of magnitude faster!)

   10 items  0.000000   0.000000   0.000000 (  0.001134)
   10 items  0.000000   0.000000   0.000000 (  0.000029)
   10 items  0.000000   0.000000   0.000000 (  0.000020)
  100 items  0.000000   0.000000   0.000000 (  0.000070)
  100 items  0.000000   0.000000   0.000000 (  0.000066)
  100 items  0.000000   0.000000   0.000000 (  0.000065)
 1000 items  0.000000   0.000000   0.000000 (  0.000612)
 1000 items  0.000000   0.000000   0.000000 (  0.000608)
 1000 items  0.000000   0.000000   0.000000 (  0.000613)
 2000 items  0.010000   0.000000   0.010000 (  0.001235)
 2000 items  0.000000   0.000000   0.000000 (  0.001282)
 2000 items  0.000000   0.000000   0.000000 (  0.001227)

With e === a || a == e || values_match?(e,a)

   10 items  0.010000   0.000000   0.010000 (  0.001258)
   10 items  0.000000   0.000000   0.000000 (  0.000034)
   10 items  0.000000   0.000000   0.000000 (  0.000027)
  100 items  0.000000   0.000000   0.000000 (  0.000124)
  100 items  0.000000   0.000000   0.000000 (  0.000151)
  100 items  0.000000   0.000000   0.000000 (  0.000121)
 1000 items  0.000000   0.000000   0.000000 (  0.001212)
 1000 items  0.000000   0.000000   0.000000 (  0.001193)
 1000 items  0.000000   0.000000   0.000000 (  0.001293)
 2000 items  0.000000   0.000000   0.000000 (  0.002433)
 2000 items  0.010000   0.000000   0.010000 (  0.002351)
 2000 items  0.000000   0.000000   0.000000 (  0.002404)

With values_match?(e,a)

   10 items  0.000000   0.000000   0.000000 (  0.001202)
   10 items  0.000000   0.000000   0.000000 (  0.000028)
   10 items  0.000000   0.000000   0.000000 (  0.000024)
  100 items  0.000000   0.000000   0.000000 (  0.000147)
  100 items  0.000000   0.000000   0.000000 (  0.000122)
  100 items  0.000000   0.000000   0.000000 (  0.000142)
 1000 items  0.000000   0.000000   0.000000 (  0.001201)
 1000 items  0.000000   0.000000   0.000000 (  0.001233)
 1000 items  0.000000   0.000000   0.000000 (  0.001221)
 2000 items  0.010000   0.000000   0.010000 (  0.002382)
 2000 items  0.000000   0.000000   0.000000 (  0.002353)
 2000 items  0.000000   0.000000   0.000000 (  0.002371)
